﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using log4net.Repository.Hierarchy;
using log4net.Appender;

namespace SewerAPI.Util
{
    /// <summary>
    /// Wrapper class for Log4Net
    /// </summary>
    public class SewerLogger
    {
        #region Private Fields

        private const string LOGNAME = "SewerLog";

        private static readonly ILog logger = LogManager.GetLogger(LOGNAME);
        private static volatile SewerLogger instance;
        private static object syncRoot = new Object();

        #endregion

        #region Public Fields

        /// <summary>
        /// Logger instance
        /// </summary>
        public static SewerLogger Instance 
        {
            get 
            {
                if (instance == null)
                {
                    lock (syncRoot) 
                    {
                        instance = new SewerLogger();
                    }
                }
                return instance;
            }
        }

        /// <summary>
        /// Base log4net object
        /// </summary>
        public Logger BaseLogger 
        {
            get
            {
                return ((Logger)logger.Logger);
            }
        }

        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        static SewerLogger(){ }

        #region Logging Methods

        /// <summary>
        /// Log info
        /// </summary>
        /// <param name="message"></param>
        public void Info(object message) 
        {
            logger.Info(message);
        }

        /// <summary>
        /// Log info with format
        /// </summary>
        /// <param name="format"></param>
        /// <param name="arg0"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        public void Info(string format, object arg0,object arg1 = null, object arg2 = null)
        {
            format = lookupResource(format);
            if (arg1 == null)
                logger.InfoFormat(format, arg0);
            else if (arg2 == null)
                logger.InfoFormat(format, arg0, arg1);
            else
                logger.InfoFormat(format, arg0, arg1, arg2);
        }

        /// <summary>
        /// Log warning
        /// </summary>
        /// <param name="message"></param>
        public void Warning(object message)
        {
            logger.Warn(message);
        }

        /// <summary>
        /// Log warning with an exception
        /// </summary>
        /// <param name="message"></param>
        /// <param name="e"></param>
        public void Warning(string message, Exception e)
        {
            message = lookupResource(message)+" "+e.Message;
            Warning(message);
            Debug(e);
        }

        /// <summary>
        /// Log warning with format
        /// </summary>
        /// <param name="format"></param>
        /// <param name="arg0"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        public void Warning(string format, object arg0, object arg1 = null, object arg2 = null)
        {
            format = lookupResource(format);
            if (arg1 == null)
                logger.WarnFormat(format, arg0);
            else if (arg2 == null)
                logger.WarnFormat(format, arg0, arg1);
            else
                logger.WarnFormat(format, arg0, arg1, arg2);
        }

        /// <summary>
        /// Log debug
        /// </summary>
        /// <param name="message"></param>
        public void Debug(object message)
        {
            if(message is Exception)
                logger.Debug(((Exception)message).StackTrace);
            else
                logger.Debug(message);
        }

        /// <summary>
        /// Log debug with format
        /// </summary>
        /// <param name="format"></param>
        /// <param name="arg0"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        public void Debug(string format, object arg0, object arg1 = null, object arg2 = null)
        {
            format = lookupResource(format);
            if (arg1 == null)
                logger.DebugFormat(format, arg0);
            else if (arg2 == null)
                logger.DebugFormat(format, arg0, arg1);
            else
                logger.DebugFormat(format, arg0, arg1, arg2);
        }

        /// <summary>
        /// Log error
        /// </summary>
        /// <param name="message"></param>
        public void Error(object message)
        {
            if (message is Exception)
                logger.Error(((Exception)message).StackTrace);
            else
                logger.Error(message);
        }

        /// <summary>
        /// Log error with format
        /// </summary>
        /// <param name="format"></param>
        /// <param name="arg0"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        public void Error(string format, object arg0, object arg1 = null, object arg2 = null)
        {
            format = lookupResource(format);
            if (arg1 == null)
            {
                if (arg0 is Exception)
                {
                    logger.ErrorFormat(format + ": " + ((Exception)arg0).Message, ((Exception)arg0).StackTrace);
                }
                else
                {
                    logger.ErrorFormat(format, arg0);
                }
            }
            else if (arg2 == null)
                logger.ErrorFormat(format, arg0, arg1);
            else
                logger.ErrorFormat(format, arg0, arg1, arg2);
            if (arg0 is Exception)
                Error(arg0);
        }

        /// <summary>
        /// Log fatal
        /// </summary>
        /// <param name="message"></param>
        public void Fatal(object message)
        {
            if (message is Exception)
                logger.Fatal(((Exception)message).StackTrace);
            else
                logger.Fatal(message);
        }

        /// <summary>
        /// Log fatal with format
        /// </summary>
        /// <param name="format"></param>
        /// <param name="arg0"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        public void Fatal(string format, object arg0, object arg1 = null, object arg2 = null)
        {
            format = lookupResource(format);
            if (arg1 == null)
                logger.FatalFormat(format, arg0);
            else if (arg2 == null)
                logger.FatalFormat(format, arg0, arg1);
            else
                logger.FatalFormat(format, arg0, arg1, arg2);
            if (arg0 is Exception)
                Fatal(arg0);
        }

        #endregion

        #region Util Methods

        /// <summary>
        /// Add an appender
        /// </summary>
        /// <param name="appender"></param>
        public void AddAppender(IAppender appender) 
        {
            BaseLogger.AddAppender(appender);
        }

        /// <summary>
        /// Remove appender
        /// </summary>
        /// <param name="appender"></param>
        public void RemoveAppender(IAppender appender)
        {
            BaseLogger.RemoveAppender(appender);
        }

        /// <summary>
        /// Remove all appenders
        /// </summary>
        public void RemoveAllAppenders() 
        {
            BaseLogger.RemoveAllAppenders();
        }

        /// <summary>
        /// Lookup a resource if found
        /// </summary>
        /// <param name="format"></param>
        /// <returns></returns>
        private string lookupResource(string format)
        {
            var _f = Resources.Strings.ResourceManager.GetString(format, Configuration.CurrentCulture);
            return (string.IsNullOrEmpty(_f)) ? format : _f;
        }

        #endregion
    }
}
